package com.huaxin.common.message.util;

import android.text.TextUtils;

import com.huaxin.common.BaseConfig;
import com.huaxin.common.Global;
import com.huaxin.common.tools.Log;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

public class Curl {

    public static final String username = "huaxin";
    public static final String password = "Hx@87775237";

    final static String signinUrl = "/broker/signin.json";
    public final static String deleteUrl = "/broker/virtual-hosts/mybroker/dsubs/clientId/action/delete";
    public final static String infoUrl = "/broker/virtual-hosts/mybroker/dsubs/clientId.json";
    final static String connectionsUrl = "/broker/connections.json?f=id&f=state&f=protocol_session_id";
    final static String CONTENT_TYPE = "Content-Type";
    final static String UTF_8 = "utf-8";
    final static String POST = "POST";
    final static String GET = "GET";
    public static final String TAG = "curl";

    static boolean isLogin = false;
    static Map<String, String> cookie = new HashMap<>();

    private static Content curl(String method, String sUrl, Map<String, String> paramMap,
                                Map<String, String> requestHeaderMap, boolean isOnlyReturnHeader) {
        Content content = null;
        HttpURLConnection httpUrlConnection = null;
        InputStream in = null;
        try {
            URL url = new URL(sUrl);
            boolean isPost = POST.equals(method);
            URLConnection urlConnection = url.openConnection();
            httpUrlConnection = (HttpURLConnection) urlConnection;
            httpUrlConnection.setRequestMethod(method);
            // Do not follow redirects, We will handle redirects ourself
            httpUrlConnection.setInstanceFollowRedirects(false);
            if (isPost) {
                urlConnection.setDoOutput(true);
                urlConnection.setDoInput(true);
            }
            urlConnection.setConnectTimeout(5000);
            urlConnection.setReadTimeout(5000);
            urlConnection.setUseCaches(false);
            urlConnection.setDefaultUseCaches(false);
            // set request header
            if (requestHeaderMap != null && !requestHeaderMap.isEmpty()) {
                for (Map.Entry<String, String> entry : requestHeaderMap.entrySet()) {
                    String key = entry.getKey();
                    String val = entry.getValue();
                    if (key != null && val != null) {
                        urlConnection.setRequestProperty(key, val);
                    }
                }
            }
            if (isPost) {
                urlConnection.setDoOutput(true);
                ByteArrayOutputStream bufOut = new ByteArrayOutputStream();
                boolean firstParam = true;
                for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                    String encName = URLEncoder.encode(entry.getKey(), UTF_8);
                    if (firstParam) {
                        firstParam = false;
                    } else {
                        bufOut.write((byte) '&');
                    }
                    String encValue = URLEncoder.encode(entry.getValue(), UTF_8);
                    bufOut.write(encName.getBytes(UTF_8));
                    bufOut.write((byte) '=');
                    bufOut.write(encValue.getBytes(UTF_8));
                }
                byte[] postContent = bufOut.toByteArray();
                ((HttpURLConnection) urlConnection).setFixedLengthStreamingMode(postContent.length);
                OutputStream postOut = urlConnection.getOutputStream();
                postOut.write(postContent);
                postOut.flush();
                postOut.close();
            }
            int responseCode = httpUrlConnection.getResponseCode();

            System.out.println("responseCode is :" + responseCode);

            // We handle redirects ourself
            if (responseCode == HttpURLConnection.HTTP_MOVED_PERM
                    || responseCode == HttpURLConnection.HTTP_MOVED_TEMP) {
                String location = httpUrlConnection.getHeaderField("Location");
                URL newAction = new URL(url, location);
                // Recurse
                StringBuffer newUrlSb = new StringBuffer(newAction.getProtocol() + "://" + newAction.getHost());
                if (newAction.getPort() != -1) {
                    newUrlSb.append(":" + newAction.getPort());
                }
                if (newAction.getPath() != null) {
                    newUrlSb.append(newAction.getPath());
                }
                if (newAction.getQuery() != null) {
                    newUrlSb.append("?" + newAction.getQuery());
                }
                if (newAction.getRef() != null) {
                    newUrlSb.append("#" + newAction.getRef());
                }
                return curl("GET", newUrlSb.toString(), null, requestHeaderMap, isOnlyReturnHeader);
            } else if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED) {
                byte[] bytes = new byte[0];
                if (!isOnlyReturnHeader) {
                    in = httpUrlConnection.getInputStream();
                    ByteArrayOutputStream bout = new ByteArrayOutputStream();
                    byte[] buf = new byte[1024];
                    while (true) {
                        int rc = in.read(buf);
                        if (rc <= 0) {
                            break;
                        } else {
                            bout.write(buf, 0, rc);
                        }
                    }
                    bytes = bout.toByteArray();
                    in.close();
                }
                // only fetch Content-Length and Last-Modified header
                String encoding = null;
                encoding = getEncodingFromContentType(httpUrlConnection.getHeaderField(CONTENT_TYPE));
                content = new Content(sUrl, new String(bytes, encoding), httpUrlConnection.getHeaderFields());
            } else if (responseCode == HttpURLConnection.HTTP_SEE_OTHER) {
                //TODO
                content = new Content(sUrl, "success", null);
            }
        } catch (Exception e) {
            if (e != null && e.getMessage() != null) {
                Log.d(e.getMessage());
            }
            return null;
        } finally {
            if (httpUrlConnection != null) {
                httpUrlConnection.disconnect();
            }
        }
        return content;
    }

    private static String getEncodingFromContentType(String contentType) {
        String encoding = null;
        if (contentType == null) {
            return null;
        }
        StringTokenizer tok = new StringTokenizer(contentType, ";");
        if (tok.hasMoreTokens()) {
            tok.nextToken();
            while (tok.hasMoreTokens()) {
                String assignment = tok.nextToken().trim();
                int eqIdx = assignment.indexOf('=');
                if (eqIdx != -1) {
                    String varName = assignment.substring(0, eqIdx).trim();
                    if ("charset".equalsIgnoreCase(varName)) {
                        String varValue = assignment.substring(eqIdx + 1).trim();
                        if (varValue.startsWith("\"") && varValue.endsWith("\"")) {
                            // substring works on indices
                            varValue = varValue.substring(1, varValue.length() - 1);
                        }
                        if (Charset.isSupported(varValue)) {
                            encoding = varValue;
                        }
                    }
                }
            }
        }
        if (encoding == null) {
            return UTF_8;
        }
        return encoding;
    }

    /**
     * 正常情况下，如果你在线，那么你在队列中的消息数应该为0，如果不为零，则所以次数消息消费存在异常。
     *
     * @param brokerName broker‘s name,default name is mybroker
     * @return return the count in queue of your self,maybe return -1 if error.
     * @See {@link #removeMqttCache}
     */
    public static int getCountOfYourself(final String brokerName) {
        final String clientId = ""+Global.user.getUserId();
        if (TextUtils.isEmpty(clientId)) return 0;
        // login
        Content content;
        if (!isLogin) {
            cookie.clear();
            final Map<String, String> paramMap = new HashMap<>();
            paramMap.put("username", username);
            paramMap.put("password", password);
            content = curl(POST, BaseConfig.getMqttHttpUrl() + signinUrl, paramMap, null, false);
            if (content == null) {
                Log.d(TAG, "singed failed : " + username);
                return -1;
            }
            // build request headers & do rate of user review
            final List<String> cookieList = content.getHeaders().get("Set-Cookie");
            if (cookieList != null && !cookieList.isEmpty()) {
                final StringBuffer sb = new StringBuffer();
                for (String val : cookieList) {
                    int pos = val.indexOf("=");
                    if (pos != -1) {
                        String cookieName = val.substring(0, pos);
                        String cookieVal = val.substring(pos + 1);
                        cookieVal = cookieVal.split(";")[0];
                        sb.append(cookieName + "=" + cookieVal + ";");
                        isLogin = true;
                        break;
                    }
                }
                Log.d("cookie is :" + sb.toString());
                cookie.put("Cookie", sb.toString());
            }
        }
        if (!isLogin) {
            Log.d(TAG, "query cookie failed : " + username);
            return -1;
        }
        final String realUrl;
        if (brokerName != null) {
            realUrl = infoUrl.replace("mybroker", brokerName).replace("clientId", clientId);
        } else {
            realUrl = infoUrl.replace("clientId", clientId);
        }
        content = curl(GET, realUrl, null, cookie, false);
        String body = content.getBody();
        int start = body.indexOf("queue_items");
        if (start > 0) {
            int end = body.indexOf(",", start + 13);
            String count = body.substring(start + 13, end);
            return Integer.parseInt(count);
        }
        return 0;
    }

    /**
     * 清除MQTT服务器相关ID的记录
     * notice you can only remove yourself's record.
     *
     * @param brokerName broker‘s name,default name is mybroker.
     * @return return true if success to remove,else return false.
     */
    public static boolean removeMqttCache(final String brokerName) {
        final String clientId = ""+ Global.user.getUserId();
        if (TextUtils.isEmpty(clientId)) return false;
        // login
        Content content;
        if (!isLogin) {
            cookie.clear();
            final Map<String, String> paramMap = new HashMap<>();
            paramMap.put("username", username);
            paramMap.put("password", password);
            content = curl(POST, BaseConfig.getMqttHttpUrl() + signinUrl, paramMap, null, false);
            if (content == null) {
                Log.d(TAG, "singed failed : " + username);
                return false;
            }
            // build request headers & do rate of user review
            final List<String> cookieList = content.getHeaders().get("Set-Cookie");
            if (cookieList != null && !cookieList.isEmpty()) {
                final StringBuffer sb = new StringBuffer();
                for (String val : cookieList) {
                    int pos = val.indexOf("=");
                    if (pos != -1) {
                        String cookieName = val.substring(0, pos);
                        String cookieVal = val.substring(pos + 1);
                        cookieVal = cookieVal.split(";")[0];
                        sb.append(cookieName + "=" + cookieVal + ";");
                        isLogin = true;
                        break;
                    }
                }
                Log.d("cookie is :" + sb.toString());
                cookie.put("Cookie", sb.toString());
            }
        }
        if (!isLogin) {
            Log.d(TAG, "query cookie failed : " + username);
            return false;
        }
        final String realUrl;
        if (brokerName != null) {
            realUrl = deleteUrl.replace("mybroker", brokerName).replace("clientId", clientId);
        } else {
            realUrl = deleteUrl.replace("clientId", clientId);
        }
        content = curl(POST, BaseConfig.getMqttHttpUrl() + realUrl, new HashMap<String, String>(), cookie, false);
        if (content == null) {
            Log.d(TAG, "query info failed : " + BaseConfig.getMqttHttpUrl() + realUrl);
            isLogin = false;
            return false;
        }
        return "success".equals(content.getBody());
    }

    /**
     * 检测指定的clientID是否在线，一般登陆时检测，如果返回true则需要轮询知道消息服务可用
     *
     * @param clientId 要查询的clientID
     * @return 如果返回大于0，表示在线或者当前MQTT服务不可用
     */
    public static int isConnected(final String clientId) {
        // login
        Content content;
        if (!isLogin) {
            cookie.clear();
            final Map<String, String> paramMap = new HashMap<>();
            paramMap.put("username", username);
            paramMap.put("password", password);
            content = curl(POST, BaseConfig.getMqttHttpUrl() + signinUrl, paramMap, null, false);
            if (content == null) {
                Log.d(TAG, "singed failed : " + username);
                return 2;
            }
            // build request headers & do rate of user review
            final List<String> cookieList = content.getHeaders().get("Set-Cookie");
            if (cookieList != null && !cookieList.isEmpty()) {
                final StringBuffer sb = new StringBuffer();
                for (String val : cookieList) {
                    int pos = val.indexOf("=");
                    if (pos != -1) {
                        String cookieName = val.substring(0, pos);
                        String cookieVal = val.substring(pos + 1);
                        cookieVal = cookieVal.split(";")[0];
                        sb.append(cookieName + "=" + cookieVal + ";");
                        isLogin = true;
                        break;
                    }
                }
                Log.d("cookie is :" + sb.toString());
                cookie.put("Cookie", sb.toString());
            }
        }
        if (!isLogin) {
            Log.d(TAG, "query cookie failed : " + username);
            return 3;
        }
        content = curl(GET, BaseConfig.getMqttHttpUrl() + connectionsUrl, null, cookie, false);
        if (content == null) {
            Log.d(TAG, "query info failed : " + BaseConfig.getMqttHttpUrl() + connectionsUrl);
            isLogin = false;
            return 4;
        }
        String body = content.getBody();
        /**
         * {"page":0,"page_size":100,"total_pages":1,"total_rows":0,"headers":["*"],"rows":[]}
         * {
         *  "page":0,
         *  "page_size":100,
         *  "total_pages":1,
         *  "total_rows":3,
         *  "headers":["id","state","protocol_session_id"],
         *  "rows":[["314","STARTED","hongcx"],["307","STARTED","hebing04"],["318","STARTED","hebing03"]]
         *  }
         */
        int start = body.indexOf("\"rows\"");
        if (start == -1) {
            return 0;
        } else {
            //[["314","STARTED","hongcx"],["307","STARTED","hebing04"],["318","STARTED","hebing03"]]
            //"314","STARTED","hongcx"],"307","STARTED","hebing04"],"318","STARTED","hebing03"]]
            body = body.substring(start + 7, body.length() - 1).trim();
            final String[] bodys = body.substring(1, body.length() - 1).replace("[", "").split("],");
            for (String b : bodys) {
                if (b.contains(clientId)) {
                    final String rep = b.replace("[", "").replace("]", "").trim();
                    Log.d("body is : " + rep + "|" + clientId);
                    //"645406","STARTED","349"
                    final String[] replaces = rep.replace("\"", "").split(",");
                    if (replaces.length == 3 && clientId.equals(replaces[2])) {
                        if ("STARTED".equals(replaces[1])) {
                            return 1;
                        } else {
                            //TODO
                            //虽然已连接，但为激活
                            return 0;
                        }
                    }
                }
            }
        }
//        body = body.substring(start + 7, body.length() - 1).trim();
//        if (body.equals("[]")) {
//            return true;
//        }
//        final String[] bodys = body.substring(1, body.length() - 1).split(",");
//        if (bodys.length == 0) {
//            return true;
//        }
//        for (String s : bodys) {
//            if (s.contains(groupClientId)) {
//                return false;
//            }
//        }
        return 0;
    }

}

class Content {
    private String url;
    private String body;
    private Map<String, List<String>> m_mHeaders = new HashMap<String, List<String>>();

    public Content(String url, String body, Map<String, List<String>> headers) {
        this.url = url;
        this.body = body;
        this.m_mHeaders = headers;
    }

    public String getUrl() {
        return url;
    }

    public String getBody() {
        return body;
    }

    public Map<String, List<String>> getHeaders() {
        return m_mHeaders;
    }

}